<%
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 版权所有（C）2018 viviworld
' 本程序为自由软件，在自由软件联盟发布的GNU通用公共许可协议的约束下，你可以对其进行再发布及修改。协议版本为第三版或（随你）更新的版本。
' 我们希望发布的这款程序有用，但不保证，甚至不保证它有经济价值和适合特定用途。详情参见GNU通用公共许可协议。
' 你理当已收到一份GNU通用公共许可协议的副本，如果没有，请查阅<http://www.gnu.org/licenses/>

' QQ: 548841861 （木鱼）
' Email： 365zph@gmail.com
' 项目地址：https://gitee.com/banrenma/RefineCMS
' 协议地址： https://gitee.com/banrenma/RefineCMS/blob/master/LICENSE
' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

%>
<% If Not DIRECT_VISIT Then Response.Write "No direct script access allowed" : Response.End%>
<%
Class cls_Parser
    Private rf_menu_id, rf_essays_id, rf_siglepage_id, rf_photos_id, rf_listinfotype_id, rf_tag_id, rf_presentation_id, rf_page
    Private tplHtml, textfile, menu, tag, presentation
    Private pattern_loop, pattern_active, pattern_normal
    Private pattern_whenIsEmpty, pattern_whenHasItems
    Private param_tagName
    Private pattern_meta_title, pattern_meta_description, pattern_meta_keywords
    Private systemTagArray

    Private Sub Class_Initialize
        ' on error resume next
        rf_menu_id = rfConvertInt(Request.QueryString(QP("rf_menu_id")))
        rf_essays_id = rfConvertInt(Request.QueryString(QP("rf_essays_id")))
        rf_siglepage_id = rfConvertInt(Request.QueryString(QP("rf_siglepage_id")))
        rf_photos_id = rfConvertInt(Request.QueryString(QP("rf_photos_id")))
        rf_listinfotype_id = rfConvertInt(Request.QueryString(QP("rf_listinfotype_id")))
        rf_tag_id = rfConvertInt(Request.QueryString(QP("rf_tag_id")))
        rf_presentation_id = rfConvertInt(Request.QueryString(QP("rf_presentation_id")))
        rf_page = rfConvertInt(Request.QueryString(QP("rf_page")))
        If rf_page = 0 Then
            rf_page = 1
        End If

        Set menu = new cls_Menu
        Set textfile = new cls_TextFile
        Set tag = new cls_Tag
        Set presentation = new cls_Presentation

        pattern_loop = "\{loop\}([\s\S]*?)\{/loop\}"
        pattern_active = "\{active\}([\s\S]*?)\{/active\}"
        pattern_normal = "\{normal\}([\s\S]*?)\{/normal\}"

        pattern_whenIsEmpty = "\{loop\}[\s\S]*?\{/loop\}|\{/{0,1}empty\}"
        pattern_whenHasItems = "{empty}[\s\S]*?{/empty}"
        pattern_meta_title = "\{\{refinecms_title\}\}"
        pattern_meta_description = "\{\{refinecms_description\}\}"
        pattern_meta_keywords = "\{\{refinecms_keywords\}\}"

        systemTagArray = Array(_
        "refinecms_sitename",_
        "refinecms_event_all",_
        "refinecms_event_db_total_hits",_
        "refinecms_event_db_total_time",_
        "refinecms_title",_
        "refinecms_description",_
        "refinecms_keywords"_
        )
       
    End Sub

    Private Sub class_terminate
        Set menu = Nothing
        Set textfile = Nothing
        Set tag = Nothing
        Set presentation = Nothing
    End Sub

    Private Function TagnameWithBracePattern
        TagnameWithBracePattern = "\{\{" & tag.sTagName & "\}\}"
    End Function

    Private Function ListPagerWithBracePattern
        ListPagerWithBracePattern = "\{\{" & tag.sTagName & "\|Pager\}\}"
    End Function

    Private Function TagnameWithBrace
        TagnameWithBrace = "{{" & tag.sTagName & "}}"
    End Function

    Private Function TagnameWithoutBrace(str)
        TagnameWithoutBrace = rfReplaceRegex(str, "(\{\{)|(\}\})", "")
    End Function

    Private Function packageTagname(param_tagName)
        packageTagname = "{{" & param_tagName & "}}"
    End Function

    Private Sub stripWhenIsEmpty
        presentation.sCodehtml = rfReplaceRegex(presentation.sCodehtml, pattern_whenIsEmpty, "")
    End Sub
    Private Sub stripWhenHasItems
        presentation.sCodehtml = rfReplaceRegex(presentation.sCodehtml, pattern_whenHasItems, "")
    End Sub

    Private Function extractLoop(param_codehtml)
        extractLoop = null
        Dim strInLoop, itemActive, itemNormal
        itemActive = ""
        itemNormal = ""

        strInLoop = rfExtractFirstSubMatch(param_codehtml, pattern_loop)
        If Not rfIsEmpty(strInLoop) Then
            itemActive = rfExtractFirstSubMatch(strInLoop, pattern_active)
            If Not rfIsEmpty(itemActive) Then
                 strInLoop = rfReplaceRegex(strInLoop, pattern_active, "")
            End If
            itemNormal = rfExtractFirstSubMatch(strInLoop, pattern_normal)
            If rfIsEmpty(itemNormal) Then
                itemNormal = strInLoop
            End If
            If rfIsEmpty(itemActive) Then
                itemActive = itemNormal
            End If
        End If
        extractLoop = Array(itemActive, itemNormal)
    End Function

    Private Sub stripASPCode
        tplHtml = rfReplaceRegex(tplHtml, "<%[\s\S]*?%"&">", "")
    End Sub

    Private Function wrapCommentOfTag(param_tag, param_finalhtml)
        If ENV_DEBUG = True Then
            wrapCommentOfTag = vbNewLine & "<!--   ######## RefineCMS 生成的代码 start  ########" & vbNewLine
            wrapCommentOfTag = wrapCommentOfTag & "标签：" & TagnameWithoutBrace(param_tag)  & vbNewLine
            wrapCommentOfTag = wrapCommentOfTag & "注：这里故意去掉两端的花括号，防止注释里的标签被当成标签再次解析。" & vbNewLine
            wrapCommentOfTag = wrapCommentOfTag & "-->"  & vbNewLine
            wrapCommentOfTag = wrapCommentOfTag & param_finalhtml & vbNewLine
            wrapCommentOfTag = wrapCommentOfTag & "<!--  ######## RefineCMS 生成的代码  end ######## -->" & vbNewLine
        Else
            wrapCommentOfTag = param_finalhtml
        End If
    End Function

    Private Sub wrapCommentOfTplfile(param_tplfile)
        If ENV_DEBUG = True Then
            Dim commentStr
            commentStr = vbNewLine & "<!--   ######## RefineCMS 加载的模板文件为：  ########" & vbNewLine
            commentStr = commentStr & "地址：" & param_tplfile  & vbNewLine
            commentStr = commentStr & "-->"  & vbNewLine
            tplHtml = commentStr & tplHtml
        End If
    End Sub

    Private Sub loadTpl
        If rf_menu_id > 0 Then
            menu.init rf_menu_id
            '文章详情页和图片详情页
            If (rf_essays_id>0 Or rf_photos_id>0) And rf_listinfotype_id=2 And rf_tag_id>0 Then
                tplHtml = textfile.ReadFile(RF_TEMPLATE_FOLDER_FRONTEND & "info_" & rf_tag_id & ".asp")
                wrapCommentOfTplfile(RF_TEMPLATE_FOLDER_FRONTEND & "info_" & rf_tag_id & ".asp")
                Exit Sub
            End If
            If (rf_essays_id>0 Or rf_photos_id>0) And rf_listinfotype_id=1 Then
                tplHtml = textfile.ReadFile(RF_TEMPLATE_FOLDER_FRONTEND & "common.asp")
                wrapCommentOfTplfile(RF_TEMPLATE_FOLDER_FRONTEND & "common.asp")
                Exit Sub
            End If
            '栏目页
            If menu.iID > 0 Then
                If menu.iMenuType = 1 Then
                    tplHtml = textfile.ReadFile(RF_TEMPLATE_FOLDER_FRONTEND & "common.asp")
                    wrapCommentOfTplfile(RF_TEMPLATE_FOLDER_FRONTEND & "common.asp")
                ElseIf menu.iMenuType = 2 Then
                    tplHtml = textfile.ReadFile(RF_TEMPLATE_FOLDER_FRONTEND & "menu_" & menu.iID & ".asp")
                    wrapCommentOfTplfile(RF_TEMPLATE_FOLDER_FRONTEND & "menu_" & menu.iID & ".asp")
                    parseMeta menu.sMenuName & " - " & RF_CMS_NAME, menu.sExcerpt, menu.sKeywords
                Else
                    rfShowErrorAuto "cls_parser.asp", T("rf_lang_menu_type_error") & ": " & menu.iMenuType
                End If
            Else
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": " & QP("rf_menu_id")
            End If
        Else
            tplHtml = textfile.ReadFile(RF_TEMPLATE_FOLDER_FRONTEND & "index.asp")
            wrapCommentOfTplfile(RF_TEMPLATE_FOLDER_FRONTEND & "index.asp")
            ' 替换title、description、keywords
            parseMeta RF_HOMEPAGE_TITLE, RF_HOMEPAGE_DESCRIPTION, RF_HOMEPAGE_KEYWORDS
        End If
    End Sub

    Private Sub parseTag()
        ' 系统级别的静态标签，放到最后或交由其它方法解析
        If rfInArray(param_tagName, systemTagArray) Then
            Exit Sub
        End If
        ' 略过 列表标签 附属的 分页标签
        If rfRegexTest(param_tagName, rfListTagPagerPattern) = True Then
            Exit Sub
        End If
        If param_tagName = "refinecms" Then
            ' 处理通用标签
            parseTagRefinecms
            Exit Sub
        End If
        If Not rfIsEmpty(param_tagName) Then
            tag.init_by_tag_name param_tagName
            If tag.sTagName = "" Then
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & packageTagname(param_tagName)
            Else
                Select Case tag.iTagType
                    Case 1
                        parseTagEssaylist
                    Case 3
                        parseTagPhotolist
                    Case 5
                        parseTagSinglepage
                    Case 6
                        parseTagBreadcrumb
                    Case 7
                        parseTagMainmenu
                    Case 8
                        parseTagSubmenu
                    Case 9
                        parseTagFriendlink
                    Case 10
                        parseTagPartial
                    Case 11
                        parserTagFlexslider
                End Select
            End If
        End If
    End Sub

    Private Sub parseTagFriendlink
        Dim arr
        arr = Split(tag.sTagText, "|", -1, 1) 
        If UBound(arr) <> 1 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_tag_tagtext_parse_error") & ": " & tag.sTagText & " : " & packageTagname(param_tagName)
        End If
        Dim friendlink, friendlinkList
        Set friendlink = new cls_Friendlink
        friendlinkList = friendlink.list(arr(0))

        presentation.init arr(1)
        If presentation.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & arr(1) & " : " & packageTagname(param_tagName)
        End If
        Dim category
        Set category = new cls_Category
        category.init arr(0)
        If category.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": categorys.id" & arr(0) & " : " & packageTagname(param_tagName)
        End If
        Dim FinalHtml
        FinalHtml = getFrindlinkList(friendlinkList, category.sCatName)
        tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, FinalHtml))
        Set friendlink = Nothing
        Set category = Nothing
    End Sub

    Private Sub parseMeta(title, description, keywords)
        tplHtml = rfReplaceRegex(tplHtml, pattern_meta_title, title)
        tplHtml = rfReplaceRegex(tplHtml, pattern_meta_description, description)
        tplHtml = rfReplaceRegex(tplHtml, pattern_meta_keywords, keywords)
    End Sub

    Private Sub parseTagRefinecms
        Dim essay, singlepage, config, ConfigArr, essayList, pager, showPage, media, mediaList
        ' 处理文章详情页
        If rf_essays_id>0 Then
            Set essay = new cls_Essay
            essay.init rf_essays_id
            If essay.iID = 0 Then
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": essays.id" & rf_essays_id
            End If
            presentation.init rf_presentation_id
            If presentation.iID = 0 Then
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & rf_presentation_id
            End If
            tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern, wrapCommentOfTag(rfCommonTag, getEssayInfo(essay)))
            ' 替换title、description、keywords
            parseMeta essay.sTitle & " - " & RF_CMS_NAME, essay.sExcerpt, essay.sKeywords
            Set essay = Nothing
            Exit Sub
        End If
        ' 处理图片详情页
        If rf_photos_id>0 Then
            Set media = new cls_Media
            media.init rf_photos_id
            If media.iID = 0 Then
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": media.id" & rf_photos_id
            End If
            presentation.init rf_presentation_id
            If presentation.iID = 0 Then
                rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & rf_presentation_id
            End If
            tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern, wrapCommentOfTag(rfCommonTag, getPhotoInfo(media)))
            ' 替换title、description、keywords
            parseMeta media.sMedianame & " - " & RF_CMS_NAME, media.sExcerpt, media.sKeywords
            Set essay = Nothing
            Exit Sub
        End If
        ' 处理栏目
        Set config = new cls_Config
        config.init "default_presentation"
        If rfIsEmpty(config.sConfigKey) Then
            rfShowError "cls_parser.asp", T("rf_lang_config_presentation_cannot_find")
        Else
            ConfigArr = Split(config.sConfigText, "|", -1, 1)
        End If
        Set config = Nothing
        If menu.iID > 0 And menu.iMenuType = 1 Then
            If menu.iIsSinglepage=1 Then
                Set singlepage = new cls_Singlepage
                singlepage.init menu.iDataID
                If singlepage.iID = 0 Then
                    rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": singlepages.id" & menu.iDataID
                End If
                presentation.init ConfigArr(7)
                If presentation.iID = 0 Then
                    rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & ConfigArr(8)
                End If
                tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern, wrapCommentOfTag(rfCommonTag, getSinglepageInfo(singlepage)))
                ' 替换title、description、keywords
                parseMeta  singlepage.sTitle & " - " & RF_CMS_NAME, singlepage.sExcerpt, singlepage.sKeywords
                Set singlepage = Nothing
            Else
                Dim category, FinalHtml
                Set category = new cls_Category
                category.init menu.iDataID
                If category.iID = 0 Then
                    rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": category.id" & menu.iDataID
                End If
                If category.iCatType = 1 Then
                    Set essay = new cls_Essay
                    essay.PageSize = ConfigArr(0)
                    essay.AbsolutePage = rf_page
                    essayList = essay.listByOrder(menu.iDataID, ConfigArr(1))
                    ' rfPrintTwoDimensionalArray essayList
                    Set pager = new cls_Pagination
                    pager.PageCount = essay.PageCount
                    pager.AbsolutePage = essay.AbsolutePage
                    pager.Style = ConfigArr(2)
                    showPage = pager.render()
                    presentation.init ConfigArr(3)
                    If presentation.iID = 0 Then
                        rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & ConfigArr(3)
                    End If
                    FinalHtml = getEssayList(essayList, ConfigArr(4), 1, 0, menu.iID)
                    tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern, wrapCommentOfTag(rfCommonTag, FinalHtml & showPage))
                    ' 替换title、description、keywords
                    parseMeta T("rf_lang_current_and_total_pagenum") & ": " & rf_page & "/" & essay.PageCount & " - " & menu.sMenuName & " - " & RF_CMS_NAME, menu.sExcerpt, menu.sKeywords
                    Set essay = Nothing
                    Set pager = Nothing
                ElseIf category.iCatType = 2 Then
                    Set media = new cls_Media
                    media.PageSize =  ConfigArr(0)
                    media.AbsolutePage = rf_page
                    mediaList = media.listByOrder(menu.iDataID, ConfigArr(1))
                    Set pager = new cls_Pagination
                    pager.PageCount = media.PageCount
                    pager.AbsolutePage = media.AbsolutePage
                    pager.Style = ConfigArr(2)
                    showPage = pager.render()
                    presentation.init ConfigArr(5)
                    If presentation.iID = 0 Then
                        rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & ConfigArr(5)
                    End If
                    FinalHtml = getPhotoList(mediaList, ConfigArr(6), 1, 0, menu.iID)
                    tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern,  wrapCommentOfTag(rfCommonTag, FinalHtml & showPage))
                    ' 替换title、description、keywords
                    parseMeta T("rf_lang_current_and_total_pagenum") & ": " & rf_page & "/" & media.PageCount & " - " & menu.sMenuName & " - " & RF_CMS_NAME, menu.sExcerpt, menu.sKeywords
                    Set media = Nothing
                    Set pager = Nothing
                ElseIf category.iCatType = 3 Then
                    Dim friendlink, friendlinkList
                    Set friendlink = new cls_Friendlink
                    friendlinkList = friendlink.list(menu.iDataID)
                    presentation.init ConfigArr(8)
                    If presentation.iID = 0 Then
                        rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & ConfigArr(8) & " : " & packageTagname(param_tagName)
                    End If
                    FinalHtml = getFrindlinkList(friendlinkList, category.sCatName)
                    tplHtml = rfReplaceRegex(tplHtml, rfCommonTagPattern, wrapCommentOfTag(rfCommonTag, FinalHtml))
                    ' 替换title、description、keywords
                    parseMeta menu.sMenuName & " - " & RF_CMS_NAME, menu.sExcerpt, menu.sKeywords
                    Set friendlink = Nothing
                End If
            End If
        End If
    End Sub

    Private Function getSinglepageInfo(singlepage)
        Dim FinalHtml, imgScale, contentLen
        FinalHtml = presentation.sCodehtml
        FinalHtml = modifierParser(FinalHtml, "{title}", singlepage.sTitle)
        FinalHtml = modifierParser(FinalHtml, "{content}", singlepage.sMainbody)
        FinalHtml = modifierParser(FinalHtml, "{excerpt}", singlepage.sExcerpt)
        FinalHtml = modifierParser(FinalHtml, "{editor}", singlepage.sUsername)
        FinalHtml = modifierParser(FinalHtml, "{updated}", singlepage.dUpdatedAt)
        FinalHtml = modifierParser(FinalHtml, "{created}", singlepage.dCreatedAt)
        FinalHtml = modifierParser(FinalHtml, "{src}",  singlepage.sFilepath)
        FinalHtml = modifierParser(FinalHtml, "{img}",  singlepage.sFilepath&"@"&singlepage.sResolution)
        getSinglepageInfo = FinalHtml
    End Function

    Private Function getEssayInfo(essay)
        Dim FinalHtml, imgScale, contentLen
        FinalHtml = presentation.sCodehtml
        FinalHtml = modifierParser(FinalHtml, "{title}", essay.sTitle)
        FinalHtml = modifierParser(FinalHtml, "{content}", essay.sMainbody)
        FinalHtml = modifierParser(FinalHtml, "{excerpt}", essay.sExcerpt)
        FinalHtml = modifierParser(FinalHtml, "{editor}", essay.sUsername)
        FinalHtml = modifierParser(FinalHtml, "{updated}", essay.dUpdatedAt)
        FinalHtml = modifierParser(FinalHtml, "{created}", essay.dCreatedAt)
        FinalHtml = modifierParser(FinalHtml, "{src}",  essay.sFilepath)
        FinalHtml = modifierParser(FinalHtml, "{img}",  essay.sFilepath&"@"&essay.sResolution)
        Dim category
        Set category = new cls_Category
        category.init essay.iCatId
        FinalHtml = modifierParser(FinalHtml, "{category}", category.sCatName)
        Set category = Nothing

        getEssayInfo = FinalHtml
    End Function

    Private Function getEssayList(essayList, param_rf_presentation_id, param_rf_listinfotype_id, param_rf_tag_id, menu_id)
        Dim FinalHtml, strInLoop
        If IsNull(essayList) Then
            stripWhenIsEmpty
            getEssayList = presentation.sCodehtml
        Else
            stripWhenHasItems
            strInLoop = rfExtractFirstSubMatch(presentation.sCodehtml, pattern_loop)
            Dim i, HtmlLoop, imgScale, url
            FinalHtml = ""
            For i=LBound(essayList, 2) to UBound(essayList, 2)
                url = rfIndexUrl & "?" & QP("rf_essays_id") & "=" & essayList(0, i)
                url = url & "&" & QP("rf_presentation_id") & "=" & param_rf_presentation_id
                url = url & "&" &  QP("rf_listinfotype_id") & "=" & param_rf_listinfotype_id
                url = url & "&" & QP("rf_tag_id") & "=" & param_rf_tag_id
                url = url & "&" & QP("rf_menu_id") & "=" & menu_id

                HtmlLoop = modifierParser(strInLoop, "{title}", essayList(3, i))
                HtmlLoop = modifierParser(HtmlLoop, "{excerpt}", essayList(5, i))
                HtmlLoop = modifierParser(HtmlLoop, "{view}", essayList(7, i))
                HtmlLoop = modifierParser(HtmlLoop, "{category}", essayList(2, i))
                HtmlLoop = modifierParser(HtmlLoop, "{editor}", essayList(4, i))
                HtmlLoop = modifierParser(HtmlLoop, "{updated}", essayList(9, i))
                HtmlLoop = modifierParser(HtmlLoop, "{created}", essayList(10, i))
                HtmlLoop = modifierParser(HtmlLoop, "{url}",  url)
                HtmlLoop = modifierParser(HtmlLoop, "{src}",  essayList(8, i))
                HtmlLoop = modifierParser(HtmlLoop, "{img}",  essayList(8, i)&"@"&essayList(11, i))
                FinalHtml = FinalHtml & HtmlLoop & vbNewLine
            Next
            FinalHtml = rfReplaceRegex(presentation.sCodehtml, pattern_loop, FinalHtml)

            getEssayList = FinalHtml
        End If
    End Function

    '------------------------------------------------- 
    ' 函数说明: 变量修饰器的处理
    ' 修饰器类型及参数参考了 Smarty：https://www.smarty.net/docs/zh_CN/language.modifiers.tpl
    '-------------------------------------------------
    Private Function modifierParser(subject, search, replaceStr)
        modifierParser = subject
        Dim subjectSrc
        subjectSrc = subject
        Dim tag, pattern_tag
        tag = rfReplaceRegex(search, "\{|\}|\s", "")
        pattern_tag = "\{" & tag & "(|[^\}]*?)?\}"
        Dim regEx, matches, match
        Set regEx = New RegExp
        regEx.Pattern = pattern_tag
        regEx.IgnoreCase = True
        regEx.Global = True
        Set matches = regEx.Execute(subject)
        For Each match in matches
            If rfIsEmpty(match.SubMatches(0)) Then
                If "{img}" = search Then
                    Dim arrNoModifier, filepathNoModifier
                    arrNoModifier = Split(replaceStr, "@", -1, 1)
                    If UBound(arrNoModifier) = 1 Then
                        filepathNoModifier = arrNoModifier(0)
                        modifierParser = rfReplace(subject, search, "<img src="""&filepathNoModifier&""" />")
                    Else
                        fmtStr = "注意：resize 修饰器只能用在 img 里。"
                    End If
                Else
                    modifierParser = rfReplace(subject, search, replaceStr)
                End If
            Else
                Dim args
                args = rfExplodeModifier(match.SubMatches(0))
                Dim fmtStr
                Select Case args(0)
                    Case "date_format"
                        If UBound(args) > 0 Then
                            fmtStr = rfFormatDate(replaceStr, args(1))
                        Else
                            fmtStr = rfFormatDate(replaceStr, "y-m-d h:i:s")
                        End If
                    Case "truncate"
                        Dim replaceStrNoTag
                        replaceStrNoTag = rfReplaceRegex(replaceStr, "<[^>]*?>", "")
                        If UBound(args) >= 2 Then
                            fmtStr = rfStrCut(replaceStrNoTag, rfConvertInt(args(1)))
                            If rfStrLen(replaceStrNoTag) > rfConvertInt(args(1)) Then
                                fmtStr = fmtStr & args(2)
                            End If
                        ElseIf UBound(args) >= 1 Then
                            fmtStr = rfStrCut(replaceStrNoTag, rfConvertInt(args(1)))
                        Else
                            fmtStr = replaceStr
                        End If
                    Case "cat"
                         If UBound(args) > 0 Then
                            fmtStr = replaceStr & args(1)
                        Else
                            fmtStr = replaceStr
                        End If
                    Case "strip_tags"
                        fmtStr = rfReplaceRegex(replaceStr, "<[^>]*?>", "")
                    Case "resize"
                        Dim arr, filepath, resolution
                        arr = Split(replaceStr, "@", -1, 1)
                        If UBound(arr) = 1 Then
                            filepath = arr(0)
                            resolution = arr(1)
                            If Not rfIsEmpty(filepath) And  Not rfIsEmpty(resolution) Then
                                If UBound(args) > 0 Then
                                    Dim w, h, arrResolution
                                    arrResolution = Split(args(1), "x", -1, 1)
                                    Dim imgScale
                                    If UBound(arrResolution) = 1 Then
                                        imgScale = rfPhotoAutoScale(arrResolution(0), arrResolution(1), resolution)
                                        fmtStr = "<img src="""&filepath&""" " &imgScale& " />"
                                    End If
                                Else
                                    imgScale = rfPhotoAutoScale(200, 200, resolution) '默认分辨率设为200x200
                                    fmtStr = "<img src="""&filepath&""" " &imgScale& " />" & "<!--  RefineCMS 提醒：由于你未正确指定图片显示的分辨率，这里默认使用了""200x200"",相当于 {img|resize:""200x200""}   -->"
                                End If
                            End If
                        Else
                            fmtStr = "注意：resize 修饰器只能用在 img 里。"
                        End If
                End Select
                modifierParser = rfReplaceRegex(subject, pattern_tag, fmtStr)
            End If
        Next 
        Set Matches = Nothing
        Set regEx = Nothing
    End Function


    Private Function getPhotoInfo(media)
        Dim FinalHtml, imgScale
        FinalHtml = presentation.sCodehtml
        FinalHtml = modifierParser(FinalHtml, "{title}", media.sMedianame)
        FinalHtml = modifierParser(FinalHtml, "{alt}", media.sAlt)
        FinalHtml = modifierParser(FinalHtml, "{resolution}", media.sResolution)
        FinalHtml = modifierParser(FinalHtml, "{filesize}", fmtFileSize(media.iFilesize))
        FinalHtml = modifierParser(FinalHtml, "{excerpt}", rfConvertStr(media.sExcerpt))
        FinalHtml = modifierParser(FinalHtml, "{editor}", media.sUsername)
        FinalHtml = modifierParser(FinalHtml, "{updated}", media.dUpdatedAt)
        FinalHtml = modifierParser(FinalHtml, "{created}", media.dCreatedAt)
        FinalHtml = modifierParser(FinalHtml, "{src}",  media.sFilepath)
        FinalHtml = modifierParser(FinalHtml, "{img}",  media.sFilepath&"@"&media.sResolution)
        Dim category
        Set category = new cls_Category
        category.init media.iCatId
        FinalHtml = modifierParser(FinalHtml, "{category}", category.sCatName)
        Set category = Nothing

        getPhotoInfo = FinalHtml
    End Function

    Private Function getPhotoList(mediaList, param_rf_presentation_id, param_rf_listinfotype_id, param_rf_tag_id, menu_id)
        Dim FinalHtml, strInLoop
        If IsNull(mediaList) Then
            stripWhenIsEmpty
            getPhotoList = presentation.sCodehtml
        Else
            stripWhenHasItems
            strInLoop = rfExtractFirstSubMatch(presentation.sCodehtml, pattern_loop)
            Dim i, HtmlLoop, imgScale, url
            FinalHtml = ""
            For i=LBound(mediaList, 2) to UBound(mediaList, 2)
                url = rfIndexUrl & "?" & QP("rf_photos_id") & "=" & mediaList(0, i)
                url = url & "&" & QP("rf_presentation_id") & "=" & param_rf_presentation_id
                url = url & "&" &  QP("rf_listinfotype_id") & "=" & param_rf_listinfotype_id
                url = url & "&" & QP("rf_tag_id") & "=" & param_rf_tag_id
                url = url & "&" & QP("rf_menu_id") & "=" & menu_id
                
            ' rfPrintTwoDimensionalArray mediaList
                HtmlLoop = modifierParser(strInLoop, "{title}", mediaList(1, i))
                HtmlLoop = modifierParser(HtmlLoop, "{url}",  url)
                HtmlLoop = modifierParser(HtmlLoop, "{alt}", rfConvertStr(mediaList(5, i)))
                HtmlLoop = modifierParser(HtmlLoop, "{resolution}", mediaList(8, i))
                HtmlLoop = modifierParser(HtmlLoop, "{filesize}", fmtFileSize(mediaList(7, i)))
                HtmlLoop = modifierParser(HtmlLoop, "{excerpt}", rfConvertStr(mediaList(13, i)))
                HtmlLoop = modifierParser(HtmlLoop, "{category}", mediaList(4, i))
                HtmlLoop = modifierParser(HtmlLoop, "{editor}", mediaList(10, i))
                HtmlLoop = modifierParser(HtmlLoop, "{updated}", mediaList(11, i))
                HtmlLoop = modifierParser(HtmlLoop, "{created}", mediaList(12, i))
                HtmlLoop = modifierParser(HtmlLoop, "{src}",  mediaList(9, i))
                HtmlLoop = modifierParser(HtmlLoop, "{img}",  mediaList(9, i)&"@"&mediaList(8, i))
                FinalHtml = FinalHtml & HtmlLoop & vbNewLine
            Next
            FinalHtml = rfReplaceRegex(presentation.sCodehtml, pattern_loop, FinalHtml)
            getPhotoList = FinalHtml
        End If
    End Function

    Private Function getFrindlinkList(friendlinkList, categoryName)
        Dim FinalHtml, strInLoop
        presentation.sCodehtml = modifierParser(presentation.sCodehtml, "{category}", categoryName)
        If IsNull(friendlinkList) Then
            stripWhenIsEmpty
            FinalHtml = presentation.sCodehtml
        Else
            stripWhenHasItems
            strInLoop = rfExtractFirstSubMatch(presentation.sCodehtml, pattern_loop)
            Dim i, HtmlLoop, imgScale
            FinalHtml = ""
            For i=LBound(friendlinkList, 2) to UBound(friendlinkList, 2)
                HtmlLoop = modifierParser(strInLoop, "{sitename}", fmtFriendlinkFontcolorText(friendlinkList(5, i), friendlinkList(1, i)) )
                HtmlLoop = modifierParser(HtmlLoop, "{siteurl}", friendlinkList(2, i))
                HtmlLoop = modifierParser(HtmlLoop, "{src}",  friendlinkList(7, i))
                HtmlLoop = modifierParser(HtmlLoop, "{img}",  friendlinkList(7, i)&"@"&friendlinkList(6, i))
                FinalHtml = FinalHtml & HtmlLoop & vbNewLine
            Next
            FinalHtml = rfReplaceRegex(presentation.sCodehtml, pattern_loop, FinalHtml)
        End If
        getFrindlinkList = FinalHtml
    End Function

    Private Sub parseTagPhotolist
        Dim arr
        arr = Split(tag.sTagText, "|", -1, 1) 
        ' 共8项
        ' 5|10|desc|10|page_number_normal|11|1|3
        ' cat_id | listnum | showorder | essay_list_pre_id | pagination | essay_info_pre_id | listinfo_tpl_type | menu_id
        If UBound(arr) <> 7 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_tag_tagtext_parse_error") & ": " & tag.sTagText & " : " & packageTagname(param_tagName)
        End If
        Dim media, mediaList
        Set media = new cls_Media
        media.PageSize = arr(1)
        media.AbsolutePage = rf_page
        mediaList = media.listByOrder(arr(0), arr(2))
        Dim pager, showPage
        Set pager = new cls_Pagination
        pager.PageCount = media.PageCount
        pager.AbsolutePage = media.AbsolutePage
        pager.Style = arr(4)
        showPage = pager.render()
        tplHtml = rfReplaceRegex(tplHtml, ListPagerWithBracePattern, showPage)
        presentation.init arr(3)
        If presentation.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & arr(3) & " : " & packageTagname(param_tagName)
        End If
        Dim FinalHtml
        FinalHtml = getPhotoList(mediaList, arr(5), arr(6), tag.iID, arr(7))
        tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, FinalHtml))
        Set media = Nothing
        Set pager = Nothing
    End Sub

    Private Sub parserTagFlexslider
        Dim arr
        arr = Split(tag.sTagText, "|", -1, 1) 
        ' 共8项
        ' 5|10|desc|10
        ' cat_id | listnum  | showorder | essay_list_pre_id
        If UBound(arr) <> 3 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_tag_tagtext_parse_error") & ": " & tag.sTagText & " : " & packageTagname(param_tagName)
        End If
        Dim media, mediaList
        Set media = new cls_Media
        media.PageSize = arr(1)
        media.AbsolutePage = rf_page
        mediaList = media.listByOrder(arr(0), arr(2))
        presentation.init arr(3)
        If presentation.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & arr(3) & " : " & packageTagname(param_tagName)
        End If
        Dim FinalHtml, strInLoop
        If IsNull(mediaList) Then
            stripWhenIsEmpty
            FinalHtml = presentation.sCodehtml
        Else
            stripWhenHasItems
            strInLoop = rfExtractFirstSubMatch(presentation.sCodehtml, pattern_loop)
            Dim i, HtmlLoop, imgScale
            FinalHtml = ""
            ' rfPrintTwoDimensionalArray mediaList
            For i=LBound(mediaList, 2) to UBound(mediaList, 2)
                HtmlLoop = modifierParser(strInLoop, "{title}", mediaList(1, i))
                HtmlLoop = modifierParser(HtmlLoop, "{alt}", rfConvertStr(mediaList(5, i)))
                HtmlLoop = modifierParser(HtmlLoop, "{excerpt}", rfConvertStr(mediaList(13, i)))
                HtmlLoop = modifierParser(HtmlLoop, "{category}", mediaList(4, i))
                HtmlLoop = modifierParser(HtmlLoop, "{src}",  mediaList(9, i))
                HtmlLoop = modifierParser(HtmlLoop, "{img}",  mediaList(9, i)&"@"&mediaList(8, i))
                FinalHtml = FinalHtml & HtmlLoop & vbNewLine
            Next
            FinalHtml = rfReplaceRegex(presentation.sCodehtml, pattern_loop, FinalHtml)
        End If
        tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, FinalHtml))
        Set media = Nothing
    End Sub

    Private Sub parseTagEssaylist
        Dim arr
        arr = Split(tag.sTagText, "|", -1, 1) 
        ' 共9项
        ' 5|10|desc|10|page_number_normal|11|1|2
        ' cat_id | listnum | showorder | essay_list_pre_id | pagination | essay_info_pre_id | listinfo_tpl_type | menu_id
        If UBound(arr) <> 7 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_tag_tagtext_parse_error") & ": " & tag.sTagText & " : " & packageTagname(param_tagName)
        End If
        Dim essay, essayList
        Set essay = new cls_Essay
        essay.PageSize = arr(1)
        essay.AbsolutePage = rf_page
        essayList = essay.listByOrder(arr(0), arr(2))
        Dim pager, showPage
        Set pager = new cls_Pagination
        pager.PageCount = essay.PageCount
        pager.AbsolutePage = essay.AbsolutePage
        pager.Style = arr(4)
        showPage = pager.render()
        tplHtml = rfReplaceRegex(tplHtml, ListPagerWithBracePattern, showPage)
        presentation.init arr(3)
        If presentation.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & arr(3) & " : " & packageTagname(param_tagName)
        End If
        Dim FinalHtml
        FinalHtml = getEssayList(essayList, arr(5), arr(6), tag.iID, arr(7))
        tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, FinalHtml))
        Set essay = Nothing
        Set pager = Nothing
    End Sub

    Private Sub parseTagSinglepage
        Dim arr
        arr = Split(tag.sTagText, "|", -1, 1) 
        ' essay_id | presentation_id
        If UBound(arr) <> 1 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_tag_tagtext_parse_error") & ": " & tag.sTagText & " : " & packageTagname(param_tagName)
        End If
        Dim singlepage
        Set singlepage = new cls_Singlepage
        singlepage.init arr(0)
        If singlepage.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": singlepages.id" & arr(0) & " : " & packageTagname(param_tagName)
        End If
        presentation.init arr(1)
        If presentation.iID = 0 Then
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & ": presentations.id" & arr(0) & " : " & packageTagname(param_tagName)
        End If
        tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, getSinglepageInfo(singlepage)))
        Set singlepage = Nothing
    End Sub

    Private Sub parseTagBreadcrumb
        Dim menuList()
        Redim Preserve menuList(1, 0)
        menuList(0, 0) = 0
        menuList(1, 0) = T("rf_lang_homepage")
        If menu.iPid = 0 Then
            Redim Preserve menuList(1, UBound(menuList,2)+1)
            menuList(0, 1) = menu.iID
            menuList(1, 1) = menu.sMenuName
        Else
            Dim menu_parent
            Set menu_parent = new cls_Menu
            menu_parent.init menu.iPid
            If menu_parent.iID > 0 Then
                Redim Preserve menuList(1, UBound(menuList,2)+1)
                menuList(0, 1) = menu_parent.iID
                menuList(1, 1) = menu_parent.sMenuName

                Redim Preserve menuList(1, UBound(menuList,2)+1)
                menuList(0, 2) = menu.iID
                menuList(1, 2) = menu.sMenuName
            End If
            Set menu_parent = Nothing
        End If
        If rf_essays_id>0 Or rf_photos_id>0 Then
            Dim itemCount
            itemCount = UBound(menuList, 2)
            Redim Preserve menuList(1, itemCount+1)
            menuList(0, itemCount+1) = -1
            menuList(1, itemCount+1) = T("rf_lang_detail")
        End If
        parseTagmenu(menuList)
    End Sub

    Private Sub parseTagmenu(menuList)
        Dim ActiveAndNormalArr, FinalHtml, tmp, i
        presentation.init tag.sTagText
        If presentation.iID > 0 Then
            If IsNull(menuList) Then
                stripWhenIsEmpty
                tplHtml = rfReplace(tplHtml, TagnameWithBrace, presentation.sCodehtml)
            Else
                stripWhenHasItems
                ActiveAndNormalArr = extractLoop(presentation.sCodehtml)
                FinalHtml = ""
                For i=LBound(menuList, 2) to UBound(menuList, 2) 
                    If menuList(0, i)=menu.iID Or menuList(0, i)=menu.iPid Then
                        tmp = ActiveAndNormalArr(0)
                    Else
                        tmp = ActiveAndNormalArr(1)
                    End If
                    tmp = rfReplace( tmp, "{menu}", menuList(1, i) )
                    If menuList(0, i) = 0 Then
                        tmp = rfReplace( tmp, "{link}", rfIndexUrl)
                    ElseIf menuList(0, i) = -1 Then '针对详情页的面包屑
                        tmp = rfReplace( tmp, "{link}", "javascript:void(0);")
                    Else
                        tmp = rfReplace( tmp, "{link}", rfIndexUrl & "?" & QP("rf_menu_id") & "=" & menuList(0, i) )
                    End If
                    FinalHtml = FinalHtml &  tmp
                Next
                tplHtml = rfReplaceRegex(tplHtml, TagnameWithBracePattern, wrapCommentOfTag(TagnameWithBrace, rfReplaceRegex(presentation.sCodehtml, pattern_loop, FinalHtml)))
            End If
        Else
            rfShowErrorAuto "cls_parser.asp", T("rf_lang_cannot_find_the_item") & packageTagname(param_tagName) & ", presentation ID=" & tag.sTagText
        End If
    End Sub

    Private Sub parseTagSubmenu
        Dim menuList
        If menu.iPid = 0 Then
            menuList = menu.list(menu.iID)
        Else
            menuList = menu.list(menu.iPid)
        End If
        parseTagmenu(menuList)
    End Sub

    Private Sub parseTagMainmenu
        Dim menuList
        menuList = menu.list(0)
        parseTagmenu(menuList)
    End Sub

    Private Sub replaceSysTag
        tplHtml = rfReplaceRegex(tplHtml, "\{\{refinecms_sitename\}\}", RF_CMS_NAME) 'title如果带有注释，会呈现在浏览器标签，影响识别
        tplHtml = rfReplaceRegex(tplHtml, "\{\{refinecms_event_db_total_time\}\}", wrapCommentOfTag("{{refinecms_event_db_total_time}}", g_timerWatcher.DbTotalTime))
        tplHtml = rfReplaceRegex(tplHtml, "\{\{refinecms_event_db_total_hits\}\}", wrapCommentOfTag("{{refinecms_event_db_total_hits}}", g_timerWatcher.DbTotalHits))
        '注意： refinecms_event_all 必须放置在 refinecms_event_db_total_time 和 refinecms_event_db_total_hits 之后，因为refinecms_event_all会有清除日志session的功能。
        tplHtml = rfReplaceRegex(tplHtml, "\{\{refinecms_event_all\}\}", wrapCommentOfTag("{{refinecms_event_all}}", g_timerWatcher.showWatcherList)) 
        g_timerWatcher.clearLastLog
    End Sub

    Private Sub loadPhotoPlugin
        Dim photoPlugin
        Set photoPlugin = new  cls_LoadPhotoPlugin
        photoPlugin.TplHtml = tplHtml
        tplHtml = photoPlugin.autoLoad
        Set photoPlugin = Nothing
    End Sub

    Private Sub parseTagPartial
        tplHtml = rfReplace(tplHtml, TagnameWithBrace, wrapCommentOfTag(TagnameWithBrace, tag.sTagText))
    End Sub

    Private Sub transform
        Dim regEx, matches, match
        Set regEx = New RegExp
        regEx.Pattern = "{{([^}]+)}}"
        regEx.IgnoreCase = True
        regEx.Global = True
        Set matches = regEx.Execute(tplHtml) 
        For Each match in matches
            rfStartWatch()
            param_tagName = match.SubMatches(0)
            parseTag()
            rfEndWatch("解析标签: "&match.SubMatches(0))
        Next 
        Set Matches = Nothing
        Set regEx = Nothing
    End Sub

    Public Sub render
        rfStartWatch()
        loadTpl
        rfEndWatch("读取模板")
        stripASPCode
        transform
        loadPhotoPlugin
        replaceSysTag
        Response.Write tplHtml
        rfPageCacheSet(tplHtml)
    End Sub

End Class
%>